package org.gordonframework.core.process {
	import org.gordonframework.core.events.GProcessEvent;
	
	import flash.events.EventDispatcher;	

	/**
	 * @author sampet
	 */
	public class GSequence extends EventDispatcher implements GProcess {

		private var queue:Array = [];
		private var index:int = 0;

		private var _progress:Number = 0;
		private var _running:Boolean = false;
		private var _complete:Boolean = false;

		private var _ignoreProcessStatus:Boolean = true;

		public function GSequence(...processes) {
			for(var i:uint = 0; i < processes.length ; i++) {
				addProcess( processes[i] );
			}			
		}

		/**
		 * The current progression of the sequence.
		 */
		public function get progress():Number {
			return _progress;
		}

		/**
		 * Indicates whether or not the sequence is running.
		 */
		public function get running():Boolean {
			return _running;
		}

		/**
		 * Indicates whether or not the sequence is comlpete.
		 */
		public function get complete():Boolean {
			return _complete;
		}

		/**
		 * If false, completed and running processes will not be started. 
		 */
		public function get ignoreProcessStatus():Boolean {
			return _ignoreProcessStatus;
		}

		public function set ignoreProcessStatus(value:Boolean):void {
			_ignoreProcessStatus = value;
		}

		
		/**
		 * Adds a process.
		 * 
		 * @param process The process to add.
		 */
		public function addProcess(process:GProcess):GProcess {
			if(process) {
				queue.push( process );
			}
			return process;
		}	

		/**
		 * Starts the sequence.
		 */
		public function start():void {
			if(_running) {
				stopCurrent( );
			}
			
			_progress = 0;
			_running = true;
			_complete = false;

			dispatchEvent( new GProcessEvent( GProcessEvent.START ) );
			
			index = -1;
			startNext( );			
		}

		/**
		 * Stops the sequence if its runnning.
		 */
		public function stop():void {
			if(_running) {
				_running = false;
				_complete = false;
				_progress = 0;
				
				stopCurrent( );
					
				dispatchEvent( new GProcessEvent( GProcessEvent.STOP ) );
			}			
		}

		private function startNext():void {
			if (index + 1 < queue.length) {
				var process:GProcess = queue[++index] as GProcess;
				
				if(!ignoreProcessStatus && process.complete) {
					startNext( );
					return;
				}

				process.addEventListener( GProcessEvent.PROGRESS, processProrgessHandler );
				process.addEventListener( GProcessEvent.COMPLETE, processCompleteHandler );
				
				if(ignoreProcessStatus || !process.running) {
					process.start( );
				}
			} else {
				_progress = 1;
				_running = false;
				_complete = true;
				
				dispatchEvent( new GProcessEvent( GProcessEvent.COMPLETE, false, false, 1 ) );
			}
		}

		private function stopCurrent():void {
			var process:GProcess = queue[index] as GProcess;
			process.removeEventListener( GProcessEvent.PROGRESS, processProrgessHandler );
			process.removeEventListener( GProcessEvent.COMPLETE, processCompleteHandler );
			process.stop( );
		}

		private function processProrgessHandler(event:GProcessEvent):void {
			_progress = index / queue.length + event.progress / queue.length; 
			dispatchEvent( new GProcessEvent( GProcessEvent.PROGRESS, false, false, progress ) );
		}		

		private function processCompleteHandler(event:GProcessEvent):void {
			//Remove listeners from current process.
			var process:GProcess = queue[index] as GProcess;
			process.removeEventListener( GProcessEvent.PROGRESS, processProrgessHandler );
			process.removeEventListener( GProcessEvent.COMPLETE, processCompleteHandler );
			
			startNext( );
		}		
	}
}
